package com.h3bpm.kumhosunny.comment.service;

import OThinker.Common.Data.Database.Database;
import OThinker.Common.Data.Database.Parameter;
import OThinker.Common.Data.DbType;
import OThinker.Common.util.ListUtil;
import OThinker.H3.Entity.IEngine;
import OThinker.H3.Entity.Notification.Notification;
import OThinker.H3.Entity.Notification.NotifyType;
import OThinker.H3.Entity.Settings.ISettingManager;
import OThinker.H3.service.factory.IService;
import com.h3bpm.base.config.PortalPropertiesUtil;
import com.h3bpm.base.operator.UserInfoOperator;
import com.h3bpm.base.res.ResBody;
import com.h3bpm.base.util.AppUtility;
import com.h3bpm.kumhosunny.comment.beans.WorkflowComment;
import com.h3bpm.kumhosunny.comment.beans.WorkflowCommentAttachment;
import com.h3bpm.kumhosunny.comment.utils.FileUploadUtil;
import com.h3bpm.kumhosunny.common.utils.SqlUtil;
import data.DataTable;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;

/**
 * @author zhengyj
 * @date 2019/8/29
 * @description 流程评论
 */
@Service
public class WorkflowCommentService implements IService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowCommentService.class);
    private static final String DingTalkMessageTitle = "%s对%s提交了新的评论";
    private static final String DEFAULT_CONTENT_PREFIX = "评论内容：";
    private UserInfoOperator userInfoOperator = new UserInfoOperator();

    public WorkflowCommentService() {
    }

    public ResBody addComment(WorkflowComment comment) {
        ResBody result = ResBody.buildFailResBody();
        boolean flag = this.writeCommentToDB(comment);
        if (!flag) {
            result.setExtendMsg("发布评论失败。");
            return result;
        } else {
                this.sendMsgToUser(comment);

            return ResBody.buildSuccessResBody();
        }
    }

    public ResBody getComments(String instanceId) {
        ResBody result = ResBody.buildFailResBody();

        try {
            Map<String, WorkflowComment> commentMap = getCommentMap(instanceId);
            if (MapUtils.isEmpty(commentMap)) {
                return ResBody.buildSuccessResBody();
            }

            List<WorkflowComment> commentList = new ArrayList<>();
            for (Map.Entry<String,WorkflowComment> entry : commentMap.entrySet()) {
                commentList.add(entry.getValue());
            }
            commentList.sort((c1, c2) -> {
                return c2.getCreatedTime().compareTo(c1.getCreatedTime());
            });
            return ResBody.buildSuccessResBody(commentList);
        } catch (Exception e) {
            result.setExtendMsg("获取评论内容失败。");
            return result;
        }
    }

    public ResBody uploadAttachment(MultipartFile file, boolean uploadByImage) {
        ResBody result = ResBody.buildFailResBody();
        String errMsg = this.validateFile(file, uploadByImage);
        if (StringUtils.isNotEmpty(errMsg)) {
            result.setExtendMsg(errMsg);
            return result;
        } else {
            String id = UUID.randomUUID().toString();
            String fileName = file.getOriginalFilename();
            String extension = FilenameUtils.getExtension(fileName);
            String tmpFileName = id;
            if (StringUtils.isNotEmpty(extension)) {
                tmpFileName = id + '.' + extension;
            }

            String path = FileUploadUtil.getFilePath(tmpFileName);

            try {
                FileUploadUtil.writeToFile(file, path);
            } catch (IOException exception) {
                errMsg = "文件上传失败";
                LOGGER.error(errMsg);
                result.setExtendMsg(errMsg);
                return result;
            }

            String url = "TempFiles" + File.separator + AppUtility.getEngine().getEngineConfig().getCode() + File.separator + tmpFileName;
            WorkflowCommentAttachment attachment = new WorkflowCommentAttachment();
            attachment.setObjectId(id);
            attachment.setDisplay(uploadByImage);
            attachment.setFileName(fileName);
            attachment.setContentType(file.getContentType());
            attachment.setContentLength(file.getSize());
            attachment.setExtension(extension);
            attachment.setUrl(url);
            result = ResBody.buildSuccessResBody(attachment);
            return result;
        }
    }

    private String validateFile(MultipartFile file, boolean uploadByImage) {
        if (null != file && file.getSize() != 0L) {
            int allowedSize = FileUploadUtil.getAllowedMaxSize(uploadByImage);
            if (file.getSize() > (long)allowedSize) {
                String errMsg = "上传文件大小超过最大限制";
                LOGGER.error(errMsg);
                return errMsg;
            } else {
                return null;
            }
        } else {
            String errMsg = "上传文件不能为空";
            LOGGER.error(errMsg);
            return errMsg;
        }
    }

    private boolean writeCommentToDB(WorkflowComment comment) {
        boolean success = false;
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String insertCommentSql = "INSERT INTO OT_WorkflowComment ( ObjectId, UserName, UserAvator, CreatedTime, ModifiedTime, InstanceId, Content, UserId, WorkItemId, NotifyUserIds ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        List<Parameter> insertCommentParams = new ArrayList();
        String workflowCommentId = UUID.randomUUID().toString();
        String userImageUrl = "";

        try {
            userImageUrl = this.userInfoOperator.GetUserImageUrl(this.userInfoOperator.GetUserInfo(comment.getUserId()));
        } catch (Exception var19) {
            userImageUrl = "";
            LOGGER.info("找不到用户头像");
        }

        insertCommentParams.add(new Parameter("ObjectID", DbType.String, workflowCommentId));
        insertCommentParams.add(new Parameter("UserName", DbType.String, comment.getUserName()));
        insertCommentParams.add(new Parameter("UserAvator", DbType.String, userImageUrl));
        insertCommentParams.add(new Parameter("CreatedTime", DbType.Date, new Date()));
        insertCommentParams.add(new Parameter("ModifiedTime", DbType.Date, new Date()));
        insertCommentParams.add(new Parameter("InstanceId", DbType.String, comment.getInstanceId()));
        insertCommentParams.add(new Parameter("Content", DbType.String, comment.getContent()));
        insertCommentParams.add(new Parameter("UserId", DbType.String, comment.getUserId()));
        insertCommentParams.add(new Parameter("WorkItemId", DbType.String, comment.getWorkItemId()));
        insertCommentParams.add(new Parameter("NotifyUserIds", DbType.String, comment.getNotifyUserIds()));
        int result = AppUtility.getPortalQuery().ExcuteNoQuery(insertCommentSql, (Parameter[]) ListUtil.toArray(insertCommentParams));
        String currentPath = request.getServletContext().getRealPath("/") + File.separator + "Portal" + File.separator;
        String insertAttachmentSql = "INSERT INTO OT_WorkflowCommentAttachment ( ObjectID, WorkflowCommentID, Extension, Description, CreatedTime, ContentType, ModifiedTime, Content, FileName, ContentLength, Url, Display ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ";
        List<WorkflowCommentAttachment> attachments = comment.getAttachments();
        if (CollectionUtils.isNotEmpty(attachments)) {
            for (WorkflowCommentAttachment attachment : attachments) {
                String url = currentPath + attachment.getUrl();
                File file = new File(url);
                if (file.exists() && file.length() > 0) {
                    try {
                        byte[] bytes = FileUtils.readFileToByteArray(file);
                        List<Parameter> insertAttachmentParams = new ArrayList();
                        insertAttachmentParams.add(new Parameter("ObjectID", DbType.String, attachment.getObjectId()));
                        insertAttachmentParams.add(new Parameter("WorkflowCommentID", DbType.String, workflowCommentId));
                        insertAttachmentParams.add(new Parameter("Extension", DbType.String, attachment.getExtension()));
                        insertAttachmentParams.add(new Parameter("Description", DbType.String, attachment.getDescription()));
                        insertAttachmentParams.add(new Parameter("CreatedTime", DbType.Date, new Date()));
                        insertAttachmentParams.add(new Parameter("ContentType", DbType.String, attachment.getContentType()));
                        insertAttachmentParams.add(new Parameter("ModifiedTime", DbType.Date, new Date()));
                        insertAttachmentParams.add(new Parameter("Content", DbType.Binary, bytes));
                        insertAttachmentParams.add(new Parameter("FileName", DbType.String, attachment.getFileName()));
                        insertAttachmentParams.add(new Parameter("ContentLength", DbType.Int64, attachment.getContentLength()));
                        insertAttachmentParams.add(new Parameter("Url", DbType.String, attachment.getUrl()));
                        insertAttachmentParams.add(new Parameter("Display", DbType.Boolean, attachment.getDisplay()));
                        AppUtility.getPortalQuery().ExcuteNoQuery(insertAttachmentSql, (Parameter[])ListUtil.toArray(insertAttachmentParams));
                    } catch (IOException var18) {
                        LOGGER.warn(var18.getMessage());
                    }
                }
            }
        }

        if (result > 0) {
            success = true;
        }

        return success;
    }

    /**
     * 发送 新的评论通知给 该流程的已办者。
     * @param comment
     */
    private void sendMsgToUser(WorkflowComment comment) {
        if (StringUtils.isNotEmpty(comment.getInstanceId())) {
            try {
                IEngine engine = AppUtility.getEngine();
                ISettingManager settingManager = engine.getSettingManager();

                // 查询 该流程 的 已办 除掉当前 评论人
                String queryWorkItemFinished = "SELECT Finisher,ObjectID from ot_workitemfinished where InstanceId = '%s' AND Finisher != '%s'  ORDER BY TokenId";
                DataTable dataTable = SqlUtil.doQuery(String.format(queryWorkItemFinished,comment.getInstanceId(),comment.getUserId()));
                Map<String,String> userWorkitemMap = new HashMap<>(0);

                if (dataTable.getRows().size() > 0) {
                    for (int i = 0 ; i < dataTable.getRows().size(); i++) {
                        userWorkitemMap.put(dataTable.getRows().get(i).getString(0),dataTable.getRows().get(i).getString(1));
                    }
                }
                    String dDUrl = settingManager.GetCustomSetting("DDUrl");
                    String dDPcUrl = settingManager.GetCustomSetting("DDPcUrl");
                    String realDDUrl = null;
                    String realDDpcUrl = null;
                    String title = String.format(DingTalkMessageTitle, engine.getOrganization().GetName(comment.getUserId()), engine.getInstanceManager().GetInstanceContext(comment.getInstanceId()).getInstanceName());

                for (String userId : userWorkitemMap.keySet()) {
                    String taskId = userWorkitemMap.get(userId);
                    realDDUrl = dDUrl.replace("{WorkItemID}", taskId);
                    realDDpcUrl = dDPcUrl.replace("{WorkItemID}", taskId);
                    Notification notification = new Notification(NotifyType.DingTalk, (String)null, (String)null, userId, (String)null, -1, comment.getInstanceId(), title, DEFAULT_CONTENT_PREFIX + comment.getContentStr(), (String)null, realDDUrl, realDDpcUrl, (String)null);
                    engine.getNotifier().Notify(notification);
                }

            } catch (Exception var20) {
                LOGGER.warn(var20.getMessage());
            }
        }

    }

    private Map<String, WorkflowComment> getCommentMap(String instanceId) throws Exception {
        Connection conn = null;
        PreparedStatement queryCommentPs = null;
        PreparedStatement queryCommentAttachPs = null;
        ResultSet resultSet = null;
        ResultSet attachResultSet = null;
        String queryCommentSql = "SELECT iwc.objectid, iwc.workitemid, iwc.content, iwc.userId, iwc.userName, iwc.userAvator, iwc.notifyUserIds, iwc.CreatedTime,iwca.objectid attachId, iwca.display, iwca.contentType, iwca.contentLength, iwca.fileName, iwca.extension, iwc.instanceId, iwca.url FROM ot_workflowcomment iwc LEFT JOIN ot_workflowcommentattachment iwca ON iwc.objectid = iwca.workflowcommentId WHERE iwc.instanceId = ? ORDER BY iwc.CreatedTime";
        String queryCommentAttachmentSql = "SELECT iwca.objectid, iwca.fileName, iwca.extension, iwca.content, iwca.url FROM ot_workflowcommentattachment iwca  WHERE iwca.objectid = ?";
        try {
            conn = getConn();
            queryCommentPs = conn.prepareStatement(queryCommentSql);
            queryCommentAttachPs = conn.prepareStatement(queryCommentAttachmentSql);

            queryCommentPs.setString(1, instanceId);

            resultSet = queryCommentPs.executeQuery();

            // 评论的Map集合
            Map<String, WorkflowComment> commentMap = new HashMap<>(3);
            while (resultSet.next()) {
                String id = resultSet.getString(1);
                // 如果该评论已经存在，则只处理其附件内容
                if (commentMap.containsKey(id)) {
                    WorkflowCommentAttachment attachment = buildAttachment(resultSet);
                    if (null != attachment) {
                        // 把附件添加到评论对象中
                        attachment.setWorkflowCommentID(id);
                        commentMap.get(id).getAttachments().add(attachment);

                        writeAttachmentToFile(queryCommentAttachPs, attachResultSet, attachment);
                    }

                } else {
                    // 如果该评论不存在
                    // 构建新的评论对象
                    WorkflowComment comment = buildComment(resultSet);
                        comment.setObjectId(id); // id

                    // 构建附件对象（不包括附件内容）
                    WorkflowCommentAttachment attachment = buildAttachment(resultSet);
                    List<WorkflowCommentAttachment> attachList = new ArrayList<>();

                    if (null != attachment) {
                        attachment.setWorkflowCommentID(id);
                        attachList.add(attachment);
                        writeAttachmentToFile(queryCommentAttachPs, attachResultSet, attachment);
                    }

                    // 设置评论对象的附件
                    comment.setAttachments(attachList);
                    // 把该评论放入Map中
                    commentMap.put(id, comment);
                }
            }
            return commentMap;
        } catch (SQLException | IOException e) {
            LOGGER.error(e.getMessage());
            throw new Exception("获取评论失败。");
        } finally {
            List<ResultSet> rsList = new ArrayList<>();
            rsList.add(resultSet);
            rsList.add(attachResultSet);

            List<PreparedStatement> psList = new ArrayList<>();
            psList.add(queryCommentPs);
            psList.add(queryCommentAttachPs);

            closeConnection(rsList, psList, conn);
        }
    }

    private boolean writeAttachmentToFile(PreparedStatement queryCommentAttachPs, ResultSet attachResultSet,
                                          WorkflowCommentAttachment attachment) throws SQLException, IOException {
        String tmpFileName = attachment.getObjectId();
        String extension = attachment.getExtension();
        // 上传文件有后缀名
        if (StringUtils.isNotEmpty(extension)) {
            tmpFileName += FilenameUtils.EXTENSION_SEPARATOR + extension;
        }
        String path = FileUploadUtil.getFilePath(tmpFileName);

        File file = new File(path);
        if (file.exists()) {
            return true;
        }

        // 查询数据库拿到附件内容
        queryCommentAttachPs.setString(1, attachment.getObjectId());
        attachResultSet = queryCommentAttachPs.executeQuery();

        InputStream is = null;
        OutputStream out = null;
        try {
            // 如果有附件，写入文件
            if (attachResultSet.next()) {
                is = attachResultSet.getBinaryStream(4);

                out = new FileOutputStream(file);
                byte[] bytes = new byte[1024];
                while (is.read(bytes, 0, 1024) != -1) {
                    out.write(bytes);
                }
            }
            return true;
        } catch (IOException ioe) {
            LOGGER.error(ioe.getMessage());
            return false;
        } finally {
            if (null != out) {
                out.close();
            }
            if (null != is) {
                is.close();
            }
        }
    }


    private WorkflowComment buildComment(ResultSet resultSet) throws SQLException {
        WorkflowComment comment = new WorkflowComment();
        comment.setWorkItemId(resultSet.getString("workitemid"));
        comment.setContent(resultSet.getString("content"));
        comment.setUserId(resultSet.getString("userId"));
        comment.setUserName(resultSet.getString("userName"));
        comment.setUserAvator(resultSet.getString("userAvator"));
        comment.setNotifyUserIds(resultSet.getString("notifyUserIds"));
        comment.setCreatedTime(resultSet.getTimestamp("CreatedTime"));
        comment.setInstanceId(resultSet.getString("instanceId"));
        return comment;
    }

    private WorkflowCommentAttachment buildAttachment(ResultSet resultSet) throws SQLException {
        String attachId = resultSet.getString(10);
        if (StringUtils.isNotEmpty(attachId)) {
            WorkflowCommentAttachment attachment = new WorkflowCommentAttachment();
            attachment.setObjectId(attachId);
            boolean display = resultSet.getBoolean("display");
            String contentType = resultSet.getString("contentType");
            long contentLength = resultSet.getLong("contentLength");
            String fileName = resultSet.getString("fileName");
            String extension = resultSet.getString("extension");
            String url = resultSet.getString("url");
            attachment.setDisplay(display);
            attachment.setContentType(contentType);
            attachment.setContentLength(contentLength);
            attachment.setFileName(fileName);
            attachment.setExtension(extension);
            attachment.setUrl(url);
            return attachment;
        } else {
            return null;
        }
    }

    public static Connection getConn() {
        Connection connection = null;

        try {
            Class.forName(Database.GetDriverString(AppUtility.getEngine().getQuery().getCommandFactory().getDatabaseType()));
        } catch (ClassNotFoundException var3) {
            ;
        }

        try {
            connection = DriverManager.getConnection(AppUtility.getEngine().getQuery().getCommandFactory().getConnectionString(), AppUtility.getEngine().getQuery().getCommandFactory().getConnectionUser(), AppUtility.getEngine().getQuery().getCommandFactory().getConnectionPassword());
        } catch (SQLException var2) {
            ;
        }

        return connection;
    }

    private void closeConnection(List<ResultSet> rsList, List<PreparedStatement> stmtList, Connection conn) {
        try {
            Iterator var4;
            if (CollectionUtils.isNotEmpty(rsList)) {
                var4 = rsList.iterator();

                while (var4.hasNext()) {
                    ResultSet rs = (ResultSet) var4.next();
                    if (null != rs) {
                        rs.close();
                    }
                }
            }

            if (CollectionUtils.isNotEmpty(stmtList)) {
                var4 = stmtList.iterator();

                while (var4.hasNext()) {
                    PreparedStatement stmt = (PreparedStatement) var4.next();
                    if (null != stmt) {
                        stmt.close();
                    }
                }
            }

            if (null != conn) {
                try {
                    conn.close();
                } catch (SQLException var6) {
                    System.out.println("关闭连接失败！");
                }
            }
        } catch (SQLException var7) {
            LOGGER.warn(var7.getMessage());
        }
    }

}

